﻿var Guid = {
    NewGuid: function () {
        var text = "0123456789abcdef";

        var result = "";

        for (var i = 0; i < 32; i++) {
            result += text.charAt(Math.floor(Math.random() * 16));
        }

        return result;
    }
};

var ESONFormat = {
    contentType: "Eson",
    encode: function (source) {
        var stringValue = this.getString(source);

        if (stringValue != null) {
            return stringValue;
        }

        if (source instanceof Array) {
            return this.encodeArray(source);
        }

        return this.encodeObject(source);
    },
    encodeArray: function (array) {
        var result = "{A|" + array.length;

        for (var i = 0; i < array.length; i++) {
            result += "|";
            result += this.encode(array[i]);
        }

        result += "}";

        return result;
    },
    encodeObject: function (object) {
        var fieldsCount = 0;
        var fieldsText = "";
        var valuesText = "";

        for (var name in object) {
            ++fieldsCount;

            fieldsText += "|";
            fieldsText += name;

            valuesText += "|";
            valuesText += this.encode(object[name]);
        }

        return "{O|" + fieldsCount + fieldsText + valuesText + "}";
    },
    getString: function (value) {
        if (value == null) {
            return "null";
        }

        if (typeof value == "string") {
            if (value.length == 0) {
                return "";
            }

            switch (value) {
                case "null":
                    return "Snull";
                case "true":
                    return "Strue";
                case "false":
                    return "Sfalse";
            }

            if (/^[0-9]+(\.[0-9]+)?$/.test(value)) {
                return "S" + value;
            }

            value = this.escape(value);

            switch (value[0]) {
                case 'S':
                case 'D':
                    return "S" + value;
            }

            return value;
        }

        if (value instanceof Date) {
            return "D" + (value.getTime());
        }

        if (typeof value == "number") {
            return String(value);
        }

        if (typeof value == "boolean") {
            return String(value);
        }

        return null;
    },
    escape: function (text) {
        if (typeof text == "string") {
            var length = text.length;

            for (var i = 0; i < text.length; i++) {
                switch (text.charAt(i)) {
                    case '~':
                    case '|':
                    case '{':
                    case '}':
                        ++length;
                        break;
                }
            }

            if (length == text.length) {
                return text;
            }

            var result = "";

            for (var i = 0; i < text.length; i++) {
                switch (text.charAt(i)) {
                    case '~':
                        result += "~";
                        result += "1";
                        break;
                    case '|':
                        result += "~";
                        result += "2";
                        break;
                    case '{':
                        result += "~";
                        result += "3";
                        break;
                    case '}':
                        result += "~";
                        result += "4";
                        break;
                    default:
                        result += text.charAt(i);
                }
            }

            return result;
        } else {
            throw "ESONFormat.escape : text 必须的 string 类型";
        }
    },
    internalDecode: function (text, begin, end, fields, values) {
        if (typeof text == "string" && typeof begin == "number" && typeof end == "number" && fields instanceof Array && values instanceof Array) {
            var type = null;

            var index = 0;
            var fieldsCount = 0;

            while (true) {
                switch (text.charAt(begin)) {
                    case '{':
                        ++begin;

                        switch (text.charAt(begin)) {
                            case 'T':
                            case 'O':
                            case 'A':
                                type = text.charAt(begin);
                                break;
                            default:
                                throw "ESONFormat.decode : 无效的 eson 格式";
                        }

                        begin += 2;

                        index = text.indexOf("|", begin, end);
                        index = index == -1 ? end : Math.min(index, end);

                        fieldsCount = parseInt(text.substring(begin, index));

                        begin = index;

                        break;
                    case '}':
                        return type;
                    case '|':
                        ++begin;

                        if (type != "A" && fields.length < fieldsCount) {
                            index = text.indexOf("|", begin, end);
                            index = index == -1 ? end : Math.min(index, end);

                            fields.push(text.substring(begin, index));
                        } else {
                            var value;

                            if (text.charAt(begin) == '{') {
                                index = this.relativeIndexOf(text, "{", "}", begin + 1, end);

                                value = this.decode(text, begin, index);

                                ++index;
                            } else {
                                index = text.indexOf("|", begin, end);
                                index = index == -1 ? end : Math.min(index, end);

                                value = this.parseValue(this.unEscape(text.substring(begin, index)));
                            }

                            values.push(value);
                        }

                        begin = index;

                        break;
                    default:
                        throw "ESONFormat.decode : 无效的 eson 格式";
                }
            }
        } else {
            throw "ESONFormat.internalDecode : 参数格式错误"
        }
    },
    unEscape: function (text) {
        if (typeof text == "string") {
            var length = text.length;
            var right = length - 1;

            for (var i = 0; i < right; i++) {
                if (text.charAt(i) == '~') {
                    --length;
                }
            }

            if (length == text.length) {
                return text;
            }

            var result = "";

            var i = 0;
            for (; i < right; ++i) {
                if (text.charAt(i) == '~') {

                    ++i;

                    switch (text.charAt(i)) {
                        case '1':
                            result += "~";
                            break;
                        case '2':
                            result += "|";
                            break;
                        case '3':
                            result += "{";
                            break;
                        case '4':
                            result += "}";
                            break;
                    }
                } else {
                    result += text.charAt(i);
                }
            }

            if (i == right) {
                result += text.charAt(i);
            }

            return result;
        } else {
            throw "ESONFormat.unEscape : 参数格式错误";
        }
    },
    parseValue: function (text) {
        if (typeof text == "string") {
            switch (text) {
                case "null":
                    return null;
                case "true":
                    return true;
                case "false":
                    return false;
            }

            if (text.length == 0) {
                return "";
            }

            switch (text.charAt(0)) {
                case 'S':
                    return text.substr(1);
                case 'D':
                    return new Date(parseInt(text.substr(1)))
            }

            if (/^[0-9]+(\.[0-9]+)?$/.test(text)) {
                return parseFloat(text);
            }

            return text;
        } else {
            throw "ESONFormat.parseValue : 参数格式错误";
        }
    },
    decode: function (text, begin, end) {
        if (begin === undefined && end === undefined) {
            begin = 0;
            end = text.length - 1;
        }

        if (typeof text == "string" && typeof begin == "number" && typeof end == "number") {

            var fields = [];
            var values = [];

            var type = this.internalDecode(text, begin, end, fields, values);

            if (type == "A") {
                return values;
            }

            var result = [];

            for (var i = 0; i < values.length; i++) {
                var name = fields[i % fields.length];
                var value = values[i];
                var index = parseInt(i / fields.length);
                if (index == result.length) {
                    result.push({});
                }
                result[index][name] = value;
            }

            if (type == "O") {
                return result[0];
            }

            return result;

        } else {
            throw "ESONFormat.decode : 参数格式错误";
        }
    },
    relativeIndexOf: function (text, beginChar, endChar, begin, end) {
        var nesting = 0;

        while (begin < end) {
            if (text.chatAt(begin) == endChar) {
                if (nesting == 0) {
                    return begin;
                }
                else {
                    --nesting;
                }
            }
            else if (text.chatAt(begin) == beginChar) {
                ++nesting;
            }

            ++begin;
        }

        return -1;
    }
}

var JSONFormat = {
    contentType: "Json",
    encode: function (source) {
        source = this.asValues(source);
        return JSON.stringify(source);
    },
    decode: function (text) {
        return eval("(" + (text || "") + ")");
    },
    asValues: function (object) {
        if (app.isElementObject(object, "INPUT")) {
            return object;
        }

        if (object instanceof Date) {
            return object.getFullYear() + "-" + (object.getMonth() + 1) + "-" + object.getDate() + " " + object.getHours() + ":" + object.getMinutes() + ":" + object.getSeconds();
        } else if (object instanceof Array) {
            for (var i = 0; i < object.length; i++) {
                object[0] = this.asValues(object[0]);
            }
        } else if (typeof object == "object") {
            for (var name in object) {
                object[name] = this.asValues(object[name]);
            }
        }

        return object;
    },
    getString: function (object) {
        return this.encode(object);
    }
}

var FormDataFormat = {
    encode: function (source) {
        source = JSONFormat.asValues(source);
        var formData = new FormData();

        for (var name in source) {
            var value = source[name];
            if (app.isElementObject(value, "INPUT")) {
                var values = this.getElementValues(value);

                for (var i = 0; i < values.length; i++) {
                    formData.append(name, values[i]);
                }
            } else {
                formData.append(name, value);
            }
        }

        return formData;
    },
    getElementValues: function (element) {
        switch (element.type) {
            case "file":
                return element.files || [element];
            default:
                return [$(element).val()];
        }
    },
    decode: function (text) {
        try {
            return JSONFormat.decode(text);
        } catch (e) {
            
        }

        try {
            return ESONFormat.decode(text);
        } catch (e) {

        }

        return {};
    }
}

var app = {
    ServerAsync: true,
    DisabledTableLoad: false,
    token: Guid.NewGuid(),
    body: $(document.body),
    defaultFormat: JSONFormat,
    defaultPrimaryKey: "Id",
    defaultFailure: function () {

    },
    defaultSuccess: function () {

    },
    IdentityKey: "Identity",
    buffered: {},
    show: function (tempFrame) {
        tempFrame = $(tempFrame);

        var frame = tempFrame.clone(true);

        frame.prop("id", "");

        frame.removeClass("temp");

        function SetZIndex(Me) {
            var ZIndex = app._ZIndex = (app._ZIndex || 0) + 1;

            Me.css("z-index", ZIndex);
        }

        SetZIndex(frame);

        frame.mousedown(function () {
            SetZIndex($(this));
        });

        frame.find(".close").click(function () {
            frame.triggerHandler("Close");

            frame.remove();
        });

        frame.find(".max").click(function () {
            if (frame.hasClass("minimized")) {
                frame.removeClass("minimized");
            } else {
                frame.toggleClass("maximized");
            }

            frame.trigger("resize");
        });

        frame.find(".min").click(function () {
            frame.addClass("minimized");
            frame.removeClass("maximized");

            frame.trigger("resize");
        });

        frame.find(".top").mousedown(function (e) {
            if (frame.hasClass("maximized")) {
                return;
            }

            var target = $(e.target);

            if (target.hasClass("min")
                || target.hasClass("max")
                || target.hasClass("close")
                || target.hasClass("right")) {
                return;
            }

            var win = $(document);

            var removeGrip = $(document.createElement("div"));


            var oX = e.clientX;
            var oY = e.clientY;

            var wWidth = win.width();
            var wHeight = win.height();

            var offset = frame.offset();

            var fWidth = frame.outerWidth();
            var fHeight = frame.outerHeight();

            removeGrip.addClass("remove-grip");

            /* 减去 Border 的宽度和高度 10 */
            removeGrip.width(fWidth - 10);
            removeGrip.height(fHeight - 10);

            move(removeGrip, offset.left, offset.top);

            app.body.append(removeGrip);

            function move(ele, x, y) {
                x = Math.max(x, 0);
                x = Math.min(x, wWidth - fWidth);
                y = Math.max(y, 0);
                y = Math.min(y, wHeight - fHeight);

                ele.css("left", Math.floor(x) + "PX");
                ele.css("top", Math.floor(y) + "PX");
            }

            function mouseMove(e) {
                e.preventDefault();

                move(removeGrip, e.clientX - oX + offset.left, e.clientY - oY + offset.top);
            }
            function mouseUp(e) {
                e.preventDefault();

                frame.css("margin-left", "0px");
                frame.css("margin-top", "0px");

                var offset = removeGrip.offset();

                move(frame, offset.left, offset.top);

                frame.triggerHandler("Move");

                win.unbind("mousemove", mouseMove);
                win.unbind("mouseup", mouseUp);

                removeGrip.remove();
            }
            win.mousemove(mouseMove);
            win.mouseup(mouseUp);
        });

        app.body.append(frame);

        /* 页面 window 大小不能容下 frame 时，调用最大化按钮。 */
        if ($(window).width() < frame.width() || $(window).height() < frame.height()) {
            frame.find(".max").click();
        }

        frame.resize(function () { app.contentLayout(frame); });

        app.contentExtend(frame);
        app.contentLayout(frame);

        frame.triggerHandler("Show");

        return frame;
    },
    showPhoto: function (url) {
        window.open(url);
    },
    contentLayout: function (content) {
        content.find(".content .fit").each(function () {
            var me = $(this);
            var parent = me.parent();
            me.outerWidth(parent.width());
            me.outerHeight(parent.height() - 44);
        });
    },
    contentExtend: function (content) {
        if (window._IsSupportPlaceholder === undefined) {
            window._IsSupportPlaceholder = "placeholder" in document.createElement("input");
        }

        if (!window._IsSupportPlaceholder) {
            if (!window._InitJQueryValMethod) {
                window._InitJQueryValMethod = true;
                $.fn.OriginalVal = $.fn.val;

                $.fn.val = function (v) {
                    if (v == undefined && this.hasClass("placeholder") && $(this).hasClass("no-value") && $(this).OriginalVal() == $(this).attr("_Placeholder")) {
                        return "";
                    }

                    return $.fn.OriginalVal.apply(this, arguments);
                }
            }
            content.find("input[type=text][placeholder]:not(.placeholder),textarea[placeholder]:not(.placeholder)").each(function () {
                var me = $(this);

                me.addClass("placeholder");

                if (me.prop("type") == "password") {
                    return;
                }

                me.attr("_Placeholder", me.attr("placeholder"));

                function MeBlur() {
                    var me = $(this);
                    if (me.val()) {
                        me.removeClass("no-value");
                    } else {
                        me.addClass("no-value");
                        me.val(me.attr("_Placeholder"));
                    }
                }

                function MeFocus() {
                    var me = $(this);
                    if (me.hasClass("no-value")) {
                        me.val("");
                    }
                }


                me.focus(MeFocus);
                me.change(MeBlur);
                me.blur(MeBlur);
                me.blur();
            });
        }
    },
    apply: function (form, data) {
        form = $(form);

        form.triggerHandler("Apply", [data]);

        for (var name in data) {
            var element = form.find("[name='" + name + "']").not(form.find(".many[name = '" + name + "']"));

            if (element.length == 0) {
                continue;
            }

            var value = data[name];

            element.each(function (index) {
                if (this.tagName == "INPUT" && (this.type == "checkbox" || this.type == "radio")) {
                    this.checked = value instanceof Array ? value.indexOf($(this).val()) != -1 : value == $(this).val();
                } else {
                    var itemValue = value instanceof Array ? value[index] : value;

                    switch (this.tagName) {
                        case "INPUT":
                        case "SELECT":
                        case "TEXTAREA":
                            $(this).val(itemValue);
                            this._ControlValue = itemValue;

                            $(this).change();
                            break;
                        case "VIDEO":
                        case "IMG":
                            this.src = itemValue;
                    }
                }
            });
        }

        form.find("[display-where]").each(function () {
            var me = $(this);
            var result = eval(me.attr("display-where"));

            if (result) {
                me.removeClass("ignore");
            } else {
                me.addClass("ignore");
            }
        });

        if (!form.hasClass("applyed")) {
            form.addClass("applyed");

            form.find("[disabled]").addClass("force-disabled").removeAttr("disabled");
        }

        form.find("[readonly-where]").each(function () {
            var me = $(this);
            var result = eval(me.attr("readonly-where"));

            if (result) {
                me.attr("readonly", "readonly");

                me.find("input").attr("disabled", "disabled");
                me.find("textarea").attr("disabled", "disabled");
                me.find(".link").addClass("ignore");
                me.find("select").attr("disabled", "disabled");
                me.find(".image-upload").addClass("disabled");
                me.find(".file-upload").addClass("disabled");
            } else {
                me.removeAttr("readonly");

                me.find("input").removeAttr("disabled");
                me.find("textarea").removeAttr("disabled");
                me.find(".link").removeClass("ignore");
                me.find("select").removeAttr("disabled");
                me.find(".image-upload").removeClass("disabled");
                me.find(".file-upload").removeClass("disabled");
            }
        });

        form.find(".force-disabled").attr("disabled", "disabled");
    },
    now: function () {
        return new Date(Date.now());
    },
    server: function (data, success, failure, url, format) {
        debugger
        $(app).triggerHandler("serverBefore", [data]);

        url = url || store.fetch('user').url;
        failure = failure || app.defaultFailure;
        success = success || app.defaultSuccess;

        for (var name in data) {
            if (app.isElementObject(data[name], "INPUT")) {
                format = "FormData";
                break;
            }
        }

        if (typeof format == "string") {
            switch (format) {
                case "Json":
                    format = JSONFormat;
                    break;
                case "FormData":
                    format = FormDataFormat;
                    break;
                case "Eson":
                case "Default":
                    format = ESONFormat;
                    break;
            }
        }

        format = format || app.defaultFormat;

        if (typeof data == "object" && typeof success == "function" && typeof failure == "function" && typeof url == "string" && typeof format == "object") {

            if (typeof data.Command != "string") {
                throw "app.server : data.Command 无效";
            }

            data = $.extend({ Token: app.token, Time: app.now(), AppId: app.appId, ContentType: "Json" }, data);

            if (app.userId && app.userName) {
                data = $.extend({ UserId: app.userId, UserName: app.userName }, data);
            }

            for (var name in data) {
                if (data[name] === app.serverRemove) {
                    delete data[name];
                }
            }

            var verify = "";

            for (var name in data) {
                verify += "&";
                verify += name;
                verify += "=";
                verify += data[name];
            }

            data.Verify = app.md5(verify.substr(1));

            var uesBuffered = app.useBuffered(data.Command);
            var bufferedKey;

            if (uesBuffered) {
                bufferedKey = url;

                for (var name in data) {
                    switch (name) {
                        case "Time":
                        case "Reload":
                        case "Verify":
                            continue;
                    }

                    bufferedKey += "&";
                    bufferedKey += name;
                    bufferedKey += "=";
                    bufferedKey += data[name];
                }

                bufferedKey = app.md5(bufferedKey);

                if (!data.Reload && app.buffered[bufferedKey]) {
                    setTimeout(function () {
                        processData(app.buffered[bufferedKey]);
                    });

                    return "buffered";
                }
            }

            $(app).triggerHandler("server", [data]);

            if (format == FormDataFormat && app.useIFrameSubmit) {

                var form = $("<form></form>");


                form.attr("action", url);
                form.attr("method", "POST");
                form.attr("enctype", "multipart/form-data");

                var iframe = $("<iframe></iframe>");

                app.appendToNoDisplay(iframe);

                function firstLoad() {
                    iframe.unbind("load", firstLoad);
                    iframe.bind("load", secondLoad);

                    $(this.contentWindow.document.body).append(form);

                    var data2 = format.encode(data);

                    for (var name in data2) {
                        switch (name) {
                            case "append":
                                continue;
                        }

                        if (app.isElementObject(data2[name], "INPUT")) {
                            var input = $(data2[name]);
                            input.attr("name", name);
                            form.append(input);
                        } else {
                            var input = $("<input/>");
                            input.attr("name", name);
                            input.val(data2[name]);
                            form.append(input);
                        }
                    }

                    form.submit();
                    form.submit();
                }

                function secondLoad() {
                    var responseText = $(this.contentWindow.document.body).text();

                    var decodeFormat = data.ContentType;

                    switch (decodeFormat) {
                        case "Json":
                            decodeFormat = JSONFormat;
                            break;
                        case "Eson":
                        case "Default":
                        default:
                            decodeFormat = ESONFormat;
                            break;
                    }

                    decodeFormat = decodeFormat || app.defaultFormat;

                    var result = decodeFormat.decode(responseText);

                    if (uesBuffered) {
                        app.buffered[bufferedKey] = result;
                    }

                    iframe.remove();

                    processData(result);
                }

                iframe.bind("load", firstLoad);

                return "iframe";
            }

            var httpRequest;

            if (window.XMLHttpRequest) {
                httpRequest = new XMLHttpRequest();
            }
            else {
                httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
            }

            httpRequest.open("POST", url, app.serverAsync);

            if (format.contentType) {
                httpRequest.setRequestHeader("Content-Type", format.contentType);
            }

            function processData(result) {
                $(app).triggerHandler("serverAfter", [data, result]);

                if (result instanceof Array) {
                    $(app).triggerHandler("serverSuccess", [data, result]);
                    success(result);
                    return;
                }

                if (typeof result == "string") {
                    $(app).triggerHandler("serverSuccess", [data, result]);
                    success(result);
                    return;
                }

                switch (result[Consts.code]) {
                    case undefined:
                    case 0x0:
                        $(app).triggerHandler("serverSuccess", [data, result]);
                        /* 成功 */
                        success(result);
                        break;
                    case 0x1:
                        /* 失败 */
                        $(app).triggerHandler("serverFailure", [data, result]);
                        app.errMsg(result[Consts.msg]);
                        failure(result);
                        break;
                    case 0x2:
                        /* 需要用户确认 */
                        app.confirm(result[Consts.msg], function () {
                            alert("TODO : 处理新命令");
                        });
                        break;
                    case 0x4:
                        /* 成功并提示 */
                        $(app).triggerHandler("serverSuccess", [data, result]);
                        app.msg(result[Consts.msg]);
                        success(result);
                        break;
                    case 0x8:
                        /* 跳转 Url */
                        $(app).triggerHandler("serverSuccess", [data, result]);
                        alert(result[Consts.msg]);
                        location = result.Url;
                        break;
                    case 0x10:
                        /* 未授权 */
                        $(app).triggerHandler("serverFailure", [data, result]);
                        alert(result[Consts.msg]);
                        failure(result);
                        location = "/";
                        break;
                }
            }

            httpRequest.onreadystatechange = function () {
                if (this.readyState == 4) {
                    if (this.status == 200) {
                        var decodeFormat = data.ContentType;

                        switch (decodeFormat) {
                            case "Json":
                                decodeFormat = JSONFormat;
                                break;
                            case "Eson":
                            case "Default":
                            default:
                                decodeFormat = ESONFormat;
                                break;
                        }

                        decodeFormat = decodeFormat || app.defaultFormat;

                        var result = decodeFormat.decode(httpRequest.responseText);

                        if (uesBuffered) {
                            app.buffered[bufferedKey] = result;
                        }

                        processData(result);
                    } else {
                        /* HTTP 错误 */
                        failure({ code: this.status, Msg: httpRequest.responseText });
                    }
                }
            }

            httpRequest.send(format.encode(data));

            return "ajax";
        } else {
            throw "app.server : 参数格式错误";
        }
    },
    useBuffered: function (commandName) {
        // 因为缓存很多时候严重影响用户体验，所以暂时禁用。
        return false;
        //if (typeof commandName == "string") {
        //    return (commandName.startsWith("Read") || commandName.startsWith("Get"));
        //} else {
        //    throw "app.useBuffered : 参数格式错误";
        //}
    },
    md5: function (text) {
        return $.md5(text);
    },
    msg: function (text) {
        alert(text);
    },
    alert: function (text) {
        alert(text);
    },
    errMsg: function (text) {
        alert(text);
    },
    confirm: function (text, callback) {
        if (confirm(text)) {
            callback();
        }
    },
    tips: function (element, text) {
        alert(text);
    },
    isElementObject: function (object, tagName) {
        if (window.Element) {
            if (!(object instanceof window.Element)) {
                return false;
            }
        } else if (!object.document) {
            return false;
        }

        if (tagName && String(tagName).toUpperCase() != String(object.tagName).toUpperCase()) {
            return false;
        }

        return true;
    },
    verifies: {
        /** 非空验证 */
        NotNull: function (Elemet, Name, Value) {
            if (Value === "" || Value === null || Value === undefined) {
                app.tips(Elemet, Name + " 不能为空！")
                return false;
            }
            return true;
        },
        /** 数字验证 */
        Number: function (Elemet, Name, Value) {
            if (!/^[0-9]+(\.[0-9]+)?$/.test(Value) && Value) {
                app.errMsg(Name + " 只能填写数字!");
                return false;
            }
            return true;
        },
        /** 电话号码或手机号码 */
        PhoneOrCellPhone: function (Elemet, Name, Value) {
            var oldErrMsg = app.errMsg;
            app.errMsg = function () { };

            if (app.verifies.CellPhone(Elemet, Name, Value)) {
                app.errMsg = oldErrMsg;
                return true;
            }

            if (app.verifies.Phone(Elemet, Name, Value)) {
                app.errMsg = oldErrMsg;
                return true;
            }

            app.errMsg = oldErrMsg;
            app.errMsg(Name + " 不是有效的电话号码或手机号码！");
            return false;
        },
        /** 手机号码 */
        CellPhone: function (Elemet, Name, Value) {
            if (!/^(\+([0-9]{2,4})-?)?1[0-9]{2}-?[0-9]{4}-?[0-9]{4}$/.test(Value) && Value) {
                app.errMsg(Name + " 不是有效的手机号码！");
                return false;
            }
            return true;
        },
        /** 电话号码 */
        Phone: function (Elemet, Name, Value) {
            if (!/^([0-9]{3,4}-?)?[0-9]{3,4}-?[0-9]{3,4}$/.test(Value) && Value) {
                app.errMsg(Name + " 不是有效的电话号码！");
                return false;
            }
            return true;
        },
        /** 身份证号码 */
        IDCard: function (Elemet, Name, Value) {
            if (!/^[0-9]{17}[0-9xX]$/.test(Value) && Value) {
                app.errMsg(Name + " 不是有效的身份证号码！");
                return false;
            }
            return true;
        }
    },
    appendToNoDisplay: function (element) {
        var NoDisplayBox = $("#_NoDisplayBox");

        if (NoDisplayBox.length == 0) {
            NoDisplayBox = $("<div id=\"_NoDisplayBox\" style=\"position:absolute;left:-9999px;top:-9999px;\"></div>");

            app.body.append(NoDisplayBox);
        }

        NoDisplayBox.append(element);
    },
    showMenu: function (items, left, top, width) {
        var Menu = $("<ul class=\"menu __menu\"></ul>");

        for (var i = 0; i < items.length; i++) {
            if (items[i] == ",") {
                Menu.append($("<a class=\"separ\"></a>"))
            } else {
                var Item = $("<li>" + items[i].Text + "</li>");

                if (items[i].Click) {
                    Item.click(items[i].Click);
                }

                Menu.append(Item);
            }
        }

        if (left) {
            Menu.css("left", left + "px");
        }
        if (top) {
            Menu.css("top", top + "px");
        }
        if (width) {
            Menu.css("width", width + "px");
        }

        app.body.append(Menu);

        if (!window.__InitMenu) {
            window.__InitMenu = true;

            $(document).click(function () {
                $(".__menu").remove();
            });
        }

        return Menu;
    },
    frameSubmit: function (Frame, Data, Callback) {

        /* 提交数据 */
        function InternalFrameSubmit(Frame, Data, Callback) {

            Frame = $(Frame);

            var Command = Frame.attr("command");

            Data = Data || {};
            var Lengths = {};

            Frame.find("[name]:not(.many [name])").each(function () {
                var Value = GetValue(this);

                if (Value == NullValue) {
                    return;
                }

                var Name = $(this).attr("name");

                Lengths[Name] = Lengths[Name] ? Lengths[Name] + 1 : 1;

                if (Lengths[Name] == 1) {
                    Data[Name] = Value;
                } else if (Lengths[Name] == 2) {
                    Data[Name] = [Data[Name], Value];
                } else {
                    Data[Name].push(Value);
                }
            });

            try {
                Frame.triggerHandler("Process", [Data]);
            } catch (e) {
                return false;
            }

            Data.Command = Command;

            app.server(Data, function (Result) {
                var PrimaryKey = Frame.attr("primary-key");

                var PrimaryValue = Data[PrimaryKey] || Result[app.IdentityKey] || Data[app.defaultPrimaryKey];

                var ManyItems = Frame.find(".many>.item:not(.many .many>.item)");

                if (ManyItems.length && !PrimaryValue) {
                    app.errMsg(Text + " 的 Many Frame 提交失败，因为该 Frame 没有设置主键(Primary-Key)属性");

                    return;
                }

                var Index = -1;

                function SubmitMany() {

                    ++Index;

                    if (Index == ManyItems.length) {
                        Frame.triggerHandler("Submitted");
                        Callback(Result);
                        return;
                    }

                    var Item = $(ManyItems[Index]);

                    var Many = Item.parents(".many:first");

                    var Field = Many.attr("field");
                    var Text = Many.attr("text");
                    var Command = Many.attr("command");

                    if (!Field) {
                        app.errMsg(Text + " Many Frame 提交失败，因为该 Many Frame 没有设置关联字段(Field)属性");

                        SubmitMany();

                        return;
                    }

                    var Data = {};

                    Data[Field] = PrimaryValue;

                    Many.removeClass("many");

                    Item.attr("text", Text);
                    Item.attr("command", Command);

                    InternalFrameSubmit(Item, Data, function (Result) { SubmitMany(); });

                    Item.removeAttr("text");
                    Item.removeAttr("command");

                    Many.addClass("many");
                }

                SubmitMany();
            });
        }


        Frame = $(Frame);

        /* 判断是否有文件正在上传 */
        if (Frame.find(".image-upload.ing").length) {
            app.alert("有图像正在上传，请稍后提交...")
            return false;
        }
        if (Frame.find(".file-upload.ing").length) {
            app.alert("有图像正在上传，请稍后提交...")
            return false;
        }

        var Command = Frame.attr("command");

        var Text = Frame.attr("text");

        Callback = Callback || function () {
            app.msg(Text + " 提交成功！");
        };

        if (!Command) {
            app.errMsg(Text + " Frame 提交失败，因为该 Frame 没有设置提交命令(Command)属性");
            return
        }

        var NullValue = {};

        function GetValue(Element) {
            if (Element.tagName == "TEXTAREA") {
                return $(Element).val();
            }
            if (Element.tagName == "INPUT") {
                switch (Element.type.toUpperCase()) {
                    case "CHECKBOX":
                    case "RADIO":
                        if (Element.checked) {
                            return $(Element).val();
                        }
                        return NullValue;
                    default:
                        return $(Element).val();
                }
            }
            if (Element.tagName == "SELECT") {
                return $(Element).val();
            }

            return NullValue;
        }

        var VerifyThrough = true;

        Frame.find("[name][verify]").each(function () {
            var Verify = $(this).attr("verify");

            if (!Verify) {
                return;
            }

            var Value = GetValue(this);

            Verify = Verify.split(",");

            var Name = $(this).attr("name");
            var Field = $(this).attr("field") || $(this).attr("placeholder") || Name;
            

            for (var j = 0; j < Verify.length; j++) {
                var VerifyFunction = app.verifies[Verify[j]];

                if (!VerifyFunction || typeof (VerifyFunction) != "function") {
                    VerifyThrough = false;

                    app.errMsg("验证器 " + Verify[j] + " 未定义或无效");
                    return false;
                }

                if (!VerifyFunction(this, Field, Value)) {
                    if (VerifyThrough) {
                        $(this).focus();
                    }

                    VerifyThrough = false;

                    break;
                }
            }
        });

        if (!VerifyThrough) {
            return false;
        }

        /* 二次确认 */
        app.confirm("确认要保存数据吗？", function () {
            InternalFrameSubmit(Frame, Data, Callback);
        });

        return false;
    },
    setParams: function (Resource, Data) {
        var Elements = $(".data-fill[resource=\"" + Resource + "\"]");

        function GetPropertyName(Element) {
            if (Element.tagName == "INPUT") {
                return "value";
            }

            return "innerHTML";
        }

        Elements.each(function () {
            var PropertyName = GetPropertyName(this);

            var Text = this._SetParams_Old_Text = (this._SetParams_Old_Text || this[PropertyName]);

            var NewText = app.format(Text, Data);

            if (NewText != Text) {
                this[PropertyName] = NewText;

                if ($(this).hasClass("only-first")) {
                    $(this).removeClass("only-first").removeClass("data-fill");
                }

                $(this).addClass("data-filled");
            }
        });
    },
    format: function (Text, Data) {
        var Regex = /@([A-Za-z0-9_]+)/g;
        var Result = "";
        var Index = 0;
        var Match;
        var HasMatch = false;

        while ((Match = Regex.exec(Text))) {
            HasMatch = true;

            Result += Text.substring(Index, Match.index);
            Result += Data[Match[1]];

            Index = Match.index + Match[0].length;
        }

        if (HasMatch && Index != Text.length) {
            Result += Text.substring(Index);
        }

        return Result;
    },
    GetDestElements: function (Element, Resource) {
        var Resources = Resource.split(",");
        var Result = $([]);

        $(Resources).each(function () {
            Result = $.merge(Result, app.GetDestElement(Element, "#" + this.trim()));
        });

        return Result;
    },
    GetDestElement: function (Element, Resource) {
        var Parent = $(Element).parent();

        while (Parent.length > 0) {
            var Result = Parent.find(Resource);

            if (Result.length) {
                return Result;
            }

            Parent = Parent.parent();
        }

        return $(Resource);
    },
    controls: {
        table: function (Element) {
            var Me = $(Element);
            var Data = Element.Data;
            var IsTable = Element._IsTable || false;

            if (!Data) {
                Data = Me.attr("data") || "";

                Data = eval("({" + Data + "})");

                Element.Data = Data;
            }

            if (!Data.Command) {
                Data.Command = Me.attr("command");
            }

            if (!Data.Command) {
                throw "无法初始化表格，因为没有指定读取数据的命令。";
            }

            var Columns = Me.find("thead tr td[name]");

            var Sorts = Me.find("thead tr td[name].sort");

            if (!IsTable) {
                /* 为排序列添加方向元素 */
                Sorts.prepend("<span class=\"sort-dir\">▼</span>");

                /* 设置排序列的点击事件 */
                Sorts.click(function () {
                    this._SortIndex = app._SortIndex = (app._SortIndex || 0) + 1;

                    var Direction = $(this).find(".sort-dir");

                    if (Direction.hasClass("asc")) {
                        Direction.removeClass("asc").addClass("desc");
                    } else if (Direction.hasClass("desc")) {
                        Direction.removeClass("desc");
                    } else {
                        Direction.addClass("asc");
                    }

                    if (Direction.hasClass("desc")) {
                        Direction.html("▲");
                    } else {
                        Direction.html("▼");
                    }

                    app.controls.table(Element);
                });

                Me.find("thead tr td[name=selection] input[type=checkbox]").click(function () {
                    if (this.checked) {
                        Me.find("tbody tr td input[type=checkbox].selection:not(:checked)").click();
                    } else {
                        Me.find("tbody tr td input[type=checkbox].selection:checked").click();
                    }
                });

                Element.GetSelected = function () {
                    var SelectedRows = Me.find("tbody tr.selected");
                    var Result = [];

                    for (var i = 0; i < SelectedRows.length; i++) {
                        Result.push($.extend({}, SelectedRows[i].Data));
                    }

                    return Result;
                };

                Element._IsTable = true;
            }

            var Orders = "";

            Sorts.sort(function (Before, After) {
                return (After._SortIndex || 0) - (Before._SortIndex || 0);
            });

            Sorts.each(function () {
                var Direction = $(this).find(".sort-dir");

                if (Direction.hasClass("asc")) {
                    Orders += ",A" + $(this).attr("name");
                } else if (Direction.hasClass("desc")) {
                    Orders += ",D" + $(this).attr("name");
                }
            });

            if (Orders) {
                Data.Orders = Orders.substr(1);
            } else {
                delete Data.Orders;
            }

            var InternalColumns = {
                selection: function (Data, Name, RowIndex, ColumnIndex) {
                    var Me = $(this);

                    var Result = document.createElement("input");

                    Result.type = "checkbox";

                    $(Result).addClass("selection");

                    $(Result).click(function () {
                        var Row = $(Me.find("tbody tr")[RowIndex]);

                        var Selection = Me.find("thead tr td[name=selection] input[type=checkbox]");

                        if (this.checked) {
                            Row.addClass("selected");

                            if (Me.find("tbody tr td input[type=checkbox].selection:checked").length == Me.find("tbody tr td input[type=checkbox].selection").length) {
                                Selection.prop("checked", true);
                            }
                        } else {
                            Row.removeClass("selected");

                            Selection.prop("checked", false);
                        }
                    });

                    Me.find("input[type=checkbox]").prop("checked", false);

                    return Result;
                },
                operation: true
            };

            if (app.DisabledTableLoad) {
                return false;
            }

            Me.triggerHandler("Load", [Data]);

            app.server(Data, function (Result) {
                if (Result.length) {
                    var FirstRow = Result[0];

                    app.setParams(Element.id, { Count: Result.length });

                    Columns.each(function () {
                        var Me = $(this);
                        var Name = Me.attr("name");

                        if (FirstRow[Name] === undefined && InternalColumns[Name] === undefined) {
                            Me.addClass("temp");
                        } else {
                            Me.removeClass("temp");
                        }
                    });

                    Columns = Me.find("thead tr td[name]:not(:hidden)");

                    var Body = $(document.createElement("tbody"));

                    for (var i = 0; i < Result.length; i++) {
                        var Tr = $(document.createElement("tr"));
                        var Data = Result[i];

                        Tr.prop("Data", Data);

                        for (var j = 0; j < Columns.length; j++) {
                            var Column = Columns[j];
                            var Name = $(Column).attr("name");
                            var Td = $(document.createElement("td"));
                            var Renderer = Column._Renderer;

                            if (!Renderer) {
                                Renderer = $(Column).attr("renderer");

                                if (Renderer) {
                                    eval("Renderer = (function(Data, Name, RowIndex, ColumnIndex){" + Renderer + "})");
                                } else if (InternalColumns[Name]) {
                                    Renderer = InternalColumns[Name];
                                } else {
                                    Renderer = function (Data, Name, RowIndex, ColumnIndex) {
                                        return Data[Name];
                                    };
                                }

                                Column._Renderer = Renderer;
                            }

                            var Value = Renderer.apply(Element, [Data, Name, i, j]);

                            if (app.isElementObject(Value)) {
                                Td.append(Value);
                                Td.prop("title", Value.innerText);
                            } else if (Value && Value.jquery) {
                                Td.append(Value);
                                Td.prop("title", Value.text());
                            } else {
                                Td.text(Value);
                                Td.prop("title", Value);
                            }

                            Tr.append(Td);
                        }

                        Body.append(Tr);
                    }

                    SetBody(Body);
                } else {
                    SetText("-V- 没有数据");
                }
            });

            function SetBody(Body) {
                Me.find("tbody").remove();
                Me.append(Body);
            }

            function SetText(Text) {
                Columns = Me.find("thead tr td[name]:not(:hidden)");

                SetBody("<tbody><tr><td colspan='" + Columns.length + "' style='height:100px;' >" + Text + "</td></tr></tbody>");
            }

            SetText("加载中...");
        },
        paging: function (Element) {
            var Me = $(Element);
            var Resource = $(Me).attr("resource");
            var DestElement = app.GetDestElement(Me, "#" + Resource)[0];
            var DestData = DestElement.Data;
            var Data = {};
            var IsPaging = Element._IsPaging || false;
            var Buttons = Element._Buttons || $();

            $.extend(Data, DestData);
            var Command = Me.attr("command");

            if (!Command) {
                throw "无法初始化分页工具，因为没有指定读取命令。";
            }

            Data.Command = Command;

            var Begin = Data.Begin;
            var End = Data.End;
            var PageSize = End - Begin + 1;

            delete Data.Begin;
            delete Data.End;

            function RefreshButtons(PageSize, Current, Total) {
                app.setParams(Element.id, { Total: Total, PageSize: PageSize, Current: Current });

                var MaxPage = Total % PageSize == 0 ? Total / PageSize : parseInt(Total / PageSize) + 1;
                var MidIndex = parseInt(Buttons.length / 2) + 1;
                var Index = Current < MidIndex ? 1 : Current + Buttons.length - MidIndex > MaxPage ? MaxPage - Buttons.length + 1 : Current - MidIndex + 1;

                Buttons.each(function () {
                    var Me = $(this);

                    $(this).val(Index);

                    if (Index > MaxPage || Index < 1) {
                        Me.addClass("temp");
                    } else {
                        Me.removeClass("temp");
                    }

                    if (Index == Current) {
                        Me.addClass("current");
                    } else {
                        Me.removeClass("current");
                    }

                    ++Index;
                });

                Me.find(".max-page").html("共 " + MaxPage + " 页");
            }

            app.server(Data, function (Result) {
                var Current = parseInt(End / PageSize);
                var Total = DestElement.Total = Element.Total = Result.Total;

                RefreshButtons(PageSize, Current, Total);
            });

            if (!IsPaging) {
                Me.find(".button[value]").each(function () {
                    if (!isNaN(parseInt($(this).val()))) {
                        Buttons.push(this);

                        $(this).val(parseInt($(this).val()));
                    }
                });

                Buttons.sort(function (Before, After) {
                    return parseInt($(Before).val()) - parseInt($(After).val());
                });

                Me.find("form").submit(function () {
                    return false;
                });

                Me.find(".button[value]").click(function () {
                    var Data = DestElement.Data;

                    var Begin = Data.Begin;
                    var End = Data.End;

                    var PageSize = End - Begin + 1;
                    var Current = parseInt(End / PageSize);

                    var Total = Element.Total;
                    var MaxPage = Total % PageSize == 0 ? Total / PageSize : parseInt(Total / PageSize) + 1;

                    var Value = $(this).val();

                    switch (Value) {
                        case "上一页":
                            Value = Current - 1;
                            break;
                        case "第一页":
                            Value = 1;
                            break;
                        case "下一页":
                            Value = Current + 1;
                            break;
                        case "最后一页": ;
                            Value = Total;
                            break;
                        case "GO":
                            var Input = $(this.parentElement).find("input[type=text]");
                            var Value = Input.val();
                            Input.val("");
                            break;
                    }

                    Value = parseInt(Value);

                    if (isNaN(Value)) {
                        Value = Current;
                    }

                    if (Value < 1) {
                        Value = 1;
                    }

                    if (Value > MaxPage) {
                        Value = MaxPage;
                    }

                    if (Value != Current) {
                        Data.Begin = (Value - 1) * PageSize + 1;
                        Data.End = Value * PageSize;

                        app.control($(DestElement));

                        RefreshButtons(PageSize, Value, Total);
                    }

                    return false;
                });

                Me.find(".first-size").html(PageSize).removeClass("first-size");

                Me.find(".filter select.input").change(function () {
                    var PageSize = parseInt($(this).val());
                    var Total = Element.Total;

                    var Data = DestElement.Data;

                    Data.Begin = 1;
                    Data.End = PageSize;

                    app.control($(DestElement));

                    RefreshButtons(PageSize, 1, Total);
                });

                Element._Buttons = Buttons;
                IsPaging = Element._IsPaging = true;
            }
        },
        content: function (Element) {
            var Me = $(Element);

            Me.find(".tools .refresh").click(function () {
                var Resource = $(this).attr("Resource");

                app.GetDestElements($(this), Resource).each(function () {
                    if (this.Data) {
                        this.Data.Reload = true;
                    }

                    app.control($(this));

                    if (this.Data) {
                        delete this.Data.Reload;
                    }
                });
            });

            Me.find(".tools .insert").click(function () {
                var Resource = $(this).attr("Resource");
                var Command = $(this).attr("Command");
                var Frame = $(this).attr("Frame");

                Frame = $(document.getElementById(Frame));

                if (Command) {
                    Frame.attr("Command", Command);
                }

                app.GetDestElements($(this), Resource).each(function () {
                    var Me = this;
                    var Flag = app.show(Frame);

                    /* 刷新 */
                    Flag.on("Submitted", function () {
                        if (Me.Data) {
                            Me.Data.Reload = true;
                        }

                        /* 如果有分页控件，则一起刷新 */
                        var Paging = app.GetDestElement(Me, ".paging[resource='" + Me.id + "']");

                        app.control($(Me));
                        app.control(Paging);

                        if (Me.Data) {
                            delete Me.Data.Reload;
                        }

                        Flag.find(".close").click();
                    });
                });
            });

            Me.find(".tools .update").click(function () {
                var Resource = $(this).attr("Resource");
                var Command = $(this).attr("Command");
                var Frame = $(this).attr("Frame");

                Frame = $(document.getElementById(Frame));

                if (Command) {
                    Frame.attr("Command", Command);
                }

                app.GetDestElements($(this), Resource).each(function () {
                    var Me = this;

                    var Selected = this.GetSelected();

                    if (Selected.length == 0) {
                        app.errMsg("请选择您要修改的数据！");
                        return;
                    }

                    for (var i = 0; i < Selected.length; i++) {
                        var Flag = app.show(Frame);

                        app.apply(Flag, $.extend({}, Selected[i]));

                        /* 刷新 */
                        Flag.on("Submitted", function () {
                            if (Me.Data) {
                                Me.Data.Reload = true;
                            }

                            app.control($(Me));

                            if (Me.Data) {
                                delete Me.Data.Reload;
                            }
                        });
                    }
                });
            });

            Me.find(".tools .delete").click(function () {
                var Resource = $(this).attr("Resource");
                var Command = $(this).attr("Command");
                var PrimaryKey = $(this).attr("PrimaryKey") || app.defaultPrimaryKey;

                app.GetDestElements($(this), Resource).each(function () {
                    var Me = this;

                    var Selected = Me.GetSelected();

                    if (Selected.length == 0) {
                        app.errMsg("请选择您要删除的数据！");
                        return;
                    }

                    app.confirm("您确定要删除这些数据吗？", function () {
                        var Id = "";

                        for (var i = 0; i < Selected.length; i++) {
                            Id += ("," + Selected[i][PrimaryKey]);
                        }

                        Id = Id.substr(1);

                        var Data = { Command: Command };

                        Data[PrimaryKey] = Id;

                        app.server(Data, function () {
                            app.msg("删除成功！");

                            /* 刷新组件 */
                            if (Me.Data) {
                                Me.Data.Reload = true;
                            }

                            app.control($(Me));

                            if (Me.Data) {
                                delete Me.Data.Reload;
                            }
                        }, function () {
                            /* 删除失败 */
                        });
                    });
                });
            });

            Me.find(".tools .exportexcel").click(function () {
                var Resource = $(this).attr("Resource");
                var FileName = $(this).attr("FileName");

                if (FileName) {
                    FileName = eval("('" + FileName + "')");
                } else {
                    FileName = "无名称";
                }

                app.GetDestElements($(this), Resource).each(function () {
                    switch (this._Control) {
                        case "table":
                            /* 有一些浏览器添加 class 后 css 样式不会马上响应。 */
                            /* 但这些 css 样式在这里非常重要，所以这里做了一些特殊处理，使 css 样式立即响应。 */
                            /* 添加一个元素，然后把这个元素移除 */

                            var Me = this;
                            $(Me).addClass("operating");

                            var Temp = $("<div class=\"temp\"></div>");

                            $(Me).append(Temp);

                            Temp.remove();

                            ExportTable(Me);

                            $(Me).removeClass("operating");

                            $(Me).append(Temp);

                            Temp.remove();
                            break;
                        default:
                            app.errMsg("只支持对表格数据导出。");
                    }
                });

                function ExportTable(Me) {
                    var Data = Me.Data;
                    var Config = [];
                    var Columns = $(Me).find("thead tr td:not(.temp)");
                    var Baseband = {
                        selection: true,
                        operation: true
                    };

                    $(Columns).each(function () {
                        var name = $(this).attr("name");

                        if (Baseband[name]) {
                            return;
                        }

                        var SortDir = $(this).find(".sort-dir");

                        SortDir.remove();

                        Config.push({
                            Name: name,
                            Display: this.innerText,
                            Width: $(this).width() * 2,
                            Row: this.parentElement.rowIndex,
                            Column: this.cellIndex,
                            RowSpan: this.rowSpan,
                            ColSpan: this.colSpan,
                            Renderer: $(this).attr("renderer")
                        });

                        $(this).prepend(SortDir);
                    });

                    for (var i = 0; i < Config.length; i++) {
                        for (var name in Config[i]) {
                            var val = Config[i][name];
                            if (val === "" || val === null || val === undefined) {
                                delete Config[i][name];
                            }
                        }
                    }

                    Data = $.extend({}, Data);
                    Data.CommandName = Data.Command;
                    Data.Command = "ExportExcel"
                    Data.Config = JSON.stringify(Config);
                    Data.FileName = FileName;

                    if (Me.Total > 1000) {
                        app.choose("当前数据较多，请选择您要导出数据范围：", {
                            "导出本页": function () {
                                app.server(Data, Download);
                            },
                            "导出前100行": function () {
                                Data.Begin = 1;
                                Data.End = 100;
                                app.server(Data, Download);
                            },
                            "导出前1000行": function () {
                                Data.Begin = 1;
                                Data.End = 1000;
                                app.server(Data, Download);
                            },
                            "导出所有": function () {
                                Data.Begin = 1;
                                Data.End = 0x7fffffff;
                                app.server(Data, Download);
                            }
                        }, 5, 500);
                    } else {
                        Data.Begin = 1;
                        Data.End = 1000;
                        app.server(Data, Download);
                    }

                    function Download(Result) {
                        /* 打开新窗口下载文件 */
                        window.open(Result.Url);
                    }
                }
            });

            Me.find(".tools .filter").submit(function (e) {
                e.stopPropagation();

                var Element = $(this).find("[name]");
                var Data = {};

                Element.each(function () {
                    var Names = $(this).attr("name").split(',');
                    var Value = $(this).val();

                    $(Names).each(function () {
                        if (Value == "") {
                            Data[this] = undefined;
                        } else {
                            Data[this] = Value;
                        }
                    });
                });

                var Resource = $(this).attr("Resource");

                app.GetDestElements($(this), Resource).each(function () {
                    if (this.Data) {
                        for (var Name in Data) {
                            if (Data[Name] === undefined) {
                                delete this.Data[Name];
                            } else {
                                this.Data[Name] = Data[Name];
                            }
                        }

                        /* 如果有分页参数，则将页面定位在第一页 */
                        if (this.Data.Begin && this.Data.End) {
                            this.Data.End = this.Data.End - this.Data.Begin + 1;
                            this.Data.Begin = 1;
                        }
                    }

                    app.control($(this));
                });

                return false;
            });

            Me.find(".toggle-filter").each(function () {
                var Resource = $(this).attr("Resource");

                var Items = $(this).find(".item");

                Items.click(function () {
                    if ($(this).hasClass("active")) {
                        return false;
                    }

                    Items.removeClass("data-fill");

                    if ($(this).hasClass("display-count")) {
                        $(this).addClass("data-fill");

                        if (!$(this).hasClass("display-count-seted-text")) {
                            $(this).html($(this).html() + "(@Total)");

                            $(this).addClass("display-count-seted-text");
                        }
                    }

                    var Data = eval("({" + $(this).val() + "})");

                    app.GetDestElements($(this), Resource).each(function () {
                        if (this.Data) {
                            $.extend(this.Data, Data);

                            for (var Item in Data) {
                                if (Data[Item] === undefined) {
                                    delete this.Data[Item];
                                }
                            }

                            /* 如果有分页参数，则将页面定位在第一页 */
                            if (this.Data.Begin && this.Data.End) {
                                this.Data.End = this.Data.End - this.Data.Begin + 1;
                                this.Data.Begin = 1;
                            }
                        }

                        app.control($(this));
                    });
                });

                function DisplayCount() {
                    var ActiveItem = null;

                    app.DisabledTableLoad = true;
                    app.ServerAsync = false;

                    Items.each(function () {
                        if ($(this).hasClass("active")) {
                            ActiveItem = this;
                        } else if ($(this).hasClass("display-count")) {
                            $(this).click();
                        }
                    });

                    if (ActiveItem) {
                        $(ActiveItem).click();
                    }

                    app.DisabledTableLoad = false;
                    app.ServerAsync = true;
                }

                if ($(this).find(".item.display-count").length > 0) {
                    setTimeout(DisplayCount);
                }
            });

            Me.find(".toggle").each(function () {
                var Items = $(this).find(".item");

                Items.click(function (e) {
                    Items.removeClass("active");

                    $(this).addClass("active");
                });
            });
        },
        tree: function (Element) {
            var Me = $(Element);
            var Root = Me.hasClass("tree") ? Me : Me.parents(".tree");
            var ParentNode = Me.hasClass("tree") ? $([]) : Me.parent("li");
            var Data = Element.Data;
            var IsTree = Root.prop("_IsTree") || false;
            var PrimaryKey = Me.attr("PrimaryKey") || app.defaultPrimaryKey;

            var CheckboxHTML = Root.hasClass("checkbox") ? "<input type=\"checkbox\"/>" : "";
            var RefreshHTML = Root.hasClass("refresh") ? "<span class=\"icon icon icon-refresh refresh\"></span>" : "";
            var InsertHTML = Root.hasClass("insert") ? "<span class=\"icon icon icon-plus insert\"></span>" : "";
            var UpdateHTML = Root.hasClass("update") ? "<span class=\"icon icon icon-edit update\"></span>" : "";
            var DeleteHTML = Root.hasClass("delete") ? "<span class=\"icon icon icon-remove delete\"></span>" : "";
            var SaveState = Root.hasClass("savestate");


            if (!Data) {
                Data = Me.attr("data") || "";

                Data = eval("({" + Data + "})");

                Element.Data = Data;
            }

            if (!Data.Command) {
                Data.Command = Me.attr("command");
            }

            if (!Data.Command) {
                throw "无法初始化树，因为没有指定读取数据的命令。";
            }

            if (!IsTree) {
                Root.each(function () {
                    this.GetSelected = function () {
                        var SelctedElement;

                        if ($(this).hasClass("checkbox")) {
                            SelctedElement = $(this).find("li>.row>input[type=checkbox]:checked").parent().parent();
                        } else {
                            SelctedElement = $(this).find("li.active");
                        }

                        var Result = [];

                        SelctedElement.each(function () {
                            Result.push($.extend({}, this.Data));
                        });

                        return Result;
                    };
                });
            }

            var ExpandedIds = Me.prop("__ExpandedIds");

            if (ExpandedIds) {
                Me.removeAttr("__ExpandedIds");
            } else {
                ExpandedIds = [];

                var ExpandedDir = Me.find("li.expanded.dir");

                ExpandedDir.each(function () {
                    if (this.Data) {
                        ExpandedIds.push(this.Data[PrimaryKey]);
                    }
                });
            }

            Me.find(">*").remove();

            Me.append("<li><div class=\"row\"><span class=\"name\">加载中...</span></div></li>");

            function AppendNode(ParentElement, Data) {
                Root.triggerHandler("Process", [Data]);

                var Type = Data.TreeType == "node" ? "node" : "dir";

                var Node = $("<li id=\"Li" + Data[PrimaryKey]+ "\"></li>");
                var Row = $("<div class=\"row\"></div>");
                var State = $("<span class=\"state icon icon-caret-right\"></span>");
                var Checkbox = $(CheckboxHTML);
                var Icon = $("<span class=\"icon " + (Data.TreeIcon || (Type == "dir" ? "icon icon-folder-close" : "icon icon-file")) + "\"></span>");
                var Text = $("<span class=\"name\">" + Data.TreeText + "</span>");
                var Children = $("<ul></ul>");
                var Right = $("<div class=\"right\"></div>");
                var Refresh = $(RefreshHTML);
                var Insert = $(InsertHTML);
                var Update = $(UpdateHTML);
                var Delete = $(DeleteHTML);
                
                Node.addClass(Type);
                Node.prop("Data", Data);

                Node.append(Row);

                Row.append(Right);

                if (Type == "dir") {
                    Node.append(Children);
                    Node.addClass("collapse");
                    Row.append(State);
                }

                if (Data.Checkbox !== false) {
                    Row.append(Checkbox);
                }

                Row.append(Icon);
                Row.append(Text);

                Right.append(Refresh);
                Right.append(Insert);
                Right.append(Update);
                Right.append(Delete);

                ParentElement.append(Node);

                if (Data.TreeTitle) {
                    Text.attr("title", Data.TreeTitle);
                }
                if (Data.Checked) {
                    Checkbox.prop("checked", true);
                }
                if (Data.Expanded) {
                    LoadChildren(Node, State, false);
                }
                if (ExpandedIds.indexOf(Data[PrimaryKey]) >= 0) {
                    Data.Expanded = true;

                    LoadChildren(Node, State, false, ExpandedIds);
                }

                State.click(function (e) {
                    LoadChildren(Node, State, false);
                    e.stopPropagation();
                });

                if (!CheckboxHTML) {
                    Row.click(function (e) {
                        if (Root.find("li.active").length == 1 && Node.hasClass("active")) {
                            return false;
                        }

                        Root.find("li.active").removeClass("active");
                        Node.addClass("active");
                        e.stopPropagation();

                        Root.triggerHandler("SelectedChange");
                    });
                }

                Row.dblclick(function (e) {
                    LoadChildren(Node, State, false);
                    e.stopPropagation();
                });

                Checkbox.click(function (e) {
                    e.stopPropagation();
                });

                Checkbox.change(function () {
                    Root.triggerHandler("SelectedChange");
                });

                Checkbox.dblclick(function (e) {
                    e.stopPropagation();
                });

                Right.click(function (e) {
                    e.stopPropagation();
                });

                Right.dblclick(function (e) {
                    e.stopPropagation();
                });

                Refresh.click(function () {
                    if (Node.hasClass("expanded")) {
                        LoadChildren(Node, State, true);
                    }

                    LoadChildren(Node, State, true);
                });

                Update.click(function () {
                    Root.each(function () {
                        var OldGetSelected = this.GetSelected;

                        this.GetSelected = function () {
                            return [$.extend({}, Data)];
                        };

                        $(".update[resource=\"" + this.id + "\"]").click();

                        this.GetSelected = OldGetSelected;
                    });
                });

                Delete.click(function () {
                    Root.each(function () {
                        var OldGetSelected = this.GetSelected;

                        this.GetSelected = function () {
                            return [$.extend({}, Data)];
                        };

                        $(".delete[resource=\"" + this.id + "\"]").click();

                        this.GetSelected = OldGetSelected;
                    });
                });

                Insert.click(function () {
                    Root.each(function () {
                        var InsertButton = $(".insert[resource=\"" + this.id + "\"]");
                        var UpdateButton = $(".update[resource=\"" + this.id + "\"]");

                        var OldUpdateCommand = UpdateButton.attr("Command");
                        UpdateButton.attr("Command", InsertButton.attr("Command"));

                        Update.click();

                        UpdateButton.attr("Command", OldUpdateCommand);
                    });
                });
            }

            function LoadChildren(Node, State, Reload, ExpandedIds) {
                if (Node.hasClass("dir")) {
                    if (Node.hasClass("collapse")) {
                        var ChildrenElement = Node.find(">ul");

                        if (!(ChildrenElement.hasClass("loaded") && SaveState)) {

                            var ChildrenData = $.extend({}, Data);

                            ChildrenData[PrimaryKey] = Node.prop("Data")[PrimaryKey];

                            if (Reload) {
                                ChildrenData.Reload = true;
                            }

                            ChildrenElement.prop("Data", ChildrenData);

                            if (ExpandedIds) {
                                ChildrenElement.prop("__ExpandedIds", ExpandedIds);
                            }

                            app.control(ChildrenElement, "tree");
                        }

                        State.removeClass("icon-caret-right").addClass("icon-caret-down");
                        Node.removeClass("collapse").addClass("expanded");

                    } else {
                        State.addClass("icon-caret-right").removeClass("icon-caret-down");
                        Node.removeClass("expanded").addClass("collapse");
                    }
                }
            }

            app.server(Data, function (Result) {

                Me.addClass("loaded");

                Me.find(">*").remove();

                $(Result).each(function () {
                    AppendNode(Me, this);
                });


                if (ParentNode.length) {
                    var ParentState = ParentNode.find(">.row>.state");

                    if (Result.length) {
                        ParentState.css("visibility", "visible");
                    } else {
                        ParentState.css("visibility", "hidden");
                    }
                }
            });

            Root.prop("_IsTree", true);
        },
        list: function (Element) {
            var Me = $(Element);
            var Data = Element.Data;
            var IsList = Element._IsList || false;
            var Value = Me.attr("Value") || "Id";
            var Display = Me.attr("Display") || "Name";
            var NoneHTML = Me.hasClass("none");
            var OldValue = Me.prop("_ControlValue") || Me.val();

            if (!Data) {
                Data = Me.attr("data") || "";

                Data = eval("({" + Data + "})");

                Element.Data = Data;
            }

            if (!Data.Command) {
                Data.Command = Me.attr("command");
            }

            if (!Data.Command) {
                throw "无法初始化表格，因为没有指定读取数据的命令。";
            }

            Me.find("*").remove();

            Me.append("<option value=\"\"> -- 加载中... --</option>");

            function AppendOption() {
                Me.triggerHandler("Process", [this]);

                if (this.Removed === true) {
                    return;
                }

                var Item = $("<option></option>")

                Item.val(this[Value]);
                Item.html(this[Display]);
                Item.prop("Data", this);

                Me.append(Item);
            }

            app.server(Data, function (Result) {
                OldValue = Me.prop("_ControlValue") || Me.val() || OldValue;

                Me.find("*").remove();

                if (NoneHTML) {
                    var NoneData = {};

                    NoneData[Value] = "";
                    NoneData[Display] = " -- 未选择 -- ";

                    AppendOption.apply(NoneData);
                }

                $(Result).each(AppendOption);

                if (OldValue) {
                    Me.val(OldValue);
                }
            });

            Element._IsList = true;
        },
        imageUpload: function (Element) {
            var Me = $(Element);

            var Box = $("<div class=\"image-upload\"></div>");
            Box.attr("style", Me.attr("style"));

            Me.removeAttr("style");
            Me.css("display", "none");

            var Preview = $("<div class=\"preview\"></div>");

            var Img = $("<img class=\"img\"/>");



            var Buttons = $("<div class=\"buttons\"></div>");

            var Upload = $("<input class=\"button upload\" type=\"button\" value=\"上传\" />");
            var Change = $("<input class=\"button change\" type=\"button\" value=\"修改\" />");
            var Remove = $("<input class=\"button remove\" type=\"button\" value=\"删除\" />");
            var Progress = $("<span class=\"progress\">正在上传图片...</span>");

            SetImgSrc();

            function SetImgSrc() {
                if (Me.val()) {
                    Img.attr("src", Me.val());
                    Box.addClass("ed");
                }
            }
            function SelectFile(e) {
                e.stopPropagation();

                var File = $("<input type=\"file\" accept=\"image/*\"/>");

                File.change(function () {

                    /* 图片正在上传 */
                    Box.addClass("ing");

                    app.server({ Command: "UploadImage", File: this }, function (Result) {
                        /* 图片上传完成 */
                        Me.val(Result["File1"]);
                        Me.change();
                        Img.attr("src", Result["File1"]);
                        Box.removeClass("ing").addClass("ed");

                        /* IFrame 提交 自动移除 */
                        try {
                            File.remove();
                        } catch (e) {

                        }
                    });
                });

                app.appendToNoDisplay(File);

                /* 兼容异步布局浏览器 */
                setTimeout(function () { File.click(); }, 100);
            }

            function RemoveFile(e) {
                e.stopPropagation();

                Box.removeClass("ed");
                Me.val("");
                Me.change();
                Img.removeAttr("src");
            }

            Upload.click(SelectFile);
            Change.click(SelectFile);
            Remove.click(RemoveFile);

            /* 查看大图 */
            Box.click(function () {
                if (Me.val()) {
                    app.showPhoto(Me.val());
                }
            });
            Box.attr("title", "点击查看大图");

            Me.change(SetImgSrc);

            Preview.append(Img);
            Buttons.append(Upload).append(Change).append(Progress);

            if ((Me.attr("verify") || "").indexOf("NotNull") == -1) {
                Buttons.append(Remove)
            }

            Box.append(Preview).append(Buttons);
            Me.after(Box);
        },
        fileUpload: function (Element) {
            var Me = $(Element);

            var Box = $("<div class=\"file-upload\"></div>");


            var Upload = $("<a class=\"upload button\">上传</a>");
            var Change = $("<a class=\"change button\">修改</a>");

            function SelectFile(e) {
                e.stopPropagation();

                var File = $("<input type=\"file\" accept=\"*/*\"/>");

                File.change(function () {
                    Box.addClass("ing");
                    Me.val("文件正在上传...");

                    app.server({ Command: "UploadFile", File: this }, function (Result) {
                        Me.val(Result["File1"]);
                        Me.change();

                        Box.removeClass("ing").addClass("ed");

                        try {
                            File.remove();
                        } catch (e) {

                        }
                    });
                });

                app.appendToNoDisplay(File);

                /* 兼容异步布局浏览器 */
                setTimeout(function () { File.click(); }, 100);
            }
            function ValueChange() {
                if (Me.val()) {
                    Box.addClass("ed");
                } else {
                    Box.removeClass("ed");
                }
            }
            function DownloadFile() {
                window.open(Me.val());
            }
            function RemoveFile(e) {
                e.stopPropagation();

                Box.removeClass("ed");
                Me.val("");
                Me.change();
            }

            Upload.click(SelectFile);
            Change.click(SelectFile);

            ValueChange();
            Me.change(ValueChange);

            Box.append(" ");
            Box.append(Upload);
            Box.append(" ");
            Box.append(Change);

            if (Me.hasClass("remove")) {
                Me.removeClass("remove");
                var Remove = $("<a class=\"remove button\">删除</a>");

                Remove.click(RemoveFile);

                Box.append(" ");
                Box.append(Remove)
            }

            if (Me.hasClass("download")) {
                Me.removeClass("download");

                var Download = $("<a class=\"download button\">下载</a>");

                Download.click(DownloadFile);

                Box.append(" ");
                Box.append(Download);
            }

            if (Me.hasClass("time")) {
                Me.removeClass("time");

                function MatchTime(Text) {
                    var timeRegex = /([1-2][0-9]{3})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})/;

                    var array = timeRegex.exec(Text);

                    if (array) {
                        var y = parseInt(array[1]), MM = parseInt(array[2]) - 1, d = parseInt(array[3]), h = parseInt(array[4]), m = parseInt(array[5]), s = parseInt(array[6]);

                        var r = new Date(y, MM, d, h, m, s);

                        if (r.getFullYear() == y && r.getMonth() == MM && r.getDate() == d && r.getHours() == h && r.getMinutes() == m && r.getSeconds() == s) {
                            return Render.Date(r);
                        }
                    }

                    return null;
                }

                var Time = $("<span class=\"time\" style=\"margin-left:10px;\"></span>");

                Box.append(" ");
                Box.append(Time);

                function MeChange() {
                    var Value = MatchTime(Me.val());

                    if (Value) {
                        Time.html("文件上传时间 : " + Value);
                        Time.removeClass("temp");
                    } else {
                        Time.addClass("temp");
                    }
                }

                MeChange();

                Me.change(MeChange);
            }

            Me.after(Box);

            Box.prepend(Me);
        },
        date: function (Element) {
            var Me = $(Element);

            function MeClick(e) {
                e.stopPropagation();

                if (Element._IsShowPanel) {
                    SetLocation($(Element).prop("__DatePanel"), Element);

                    return false;
                }

                Element._IsShowPanel = true;

                RemoveOtherDatePanel();

                var Value = Me.val();

                if (Value) {
                    Value = new Date(Date.parse(Value));
                    Me.val(FormatDate(Value, true));
                    Me.change();
                } else {
                    Value = app.now();
                }

                var Year = Value.getFullYear();
                var Month = Value.getMonth() + 1;
                var Day = Value.getDate();

                var MinDay = 1;

                var MaxDay = new Date(Year, Month, 1);
                MaxDay.setDate(0);
                MaxDay = MaxDay.getDate();

                var Days = [];

                Value.setDate(MinDay);
                var MinWeek = Value.getDay();

                Value.setDate(MaxDay);
                var MaxWeek = Value.getDay();

                Value.setDate(MinDay - 1);

                // 当月日期之前
                for (var i = MinWeek - 1, j = Value.getDate() ; i >= 0; --i) {
                    Days.push({ Value: j - i, Type: "last" });
                }

                /* 当月日期 */
                for (var i = MinDay; i <= MaxDay; i++) {
                    if (i == Day) {
                        Days.push({ Value: i, Type: "selected" });
                    } else {
                        Days.push({ Value: i, Type:"" });
                    }
                }

                Value.setDate(MinDay);
                Value.setMonth(Month);

                /* 当月日期之后 */
                for (var i = MaxWeek, j = Value.getDate() ; i < 6; ++i, ++j) {
                    Days.push({ Value: j, Type: "next" });
                }

                var DaysHtml = "";

                for (var i = 0; i < Days.length; i++) {
                    DaysHtml += "<i class=\"" + Days[i].Type + "\">" + Days[i].Value + "</i>";
                }

                var Panel = $("<div class=\"date-panel\"><div class=\"top\"><div class=\"year\"><input class=\"button\" type=\"button\" value=\"<\"/><input class=\"input\" type=\"text\" /><input class=\"button\" type=\"button\" value=\">\" />" +
                    "</div><div class=\"month\"><input class=\"button\" type=\"button\" value=\"<\" /><input class=\"input\" type=\"text\" /><input class=\"button\" type=\"button\" value=\">\" /></div></div><div class=\"content\"><div class=\"week\">" +
                    "<i>日</i><i>一</i><i>二</i><i>三</i><i>四</i><i>五</i><i>六</i></div><div class=\"days\">"
                    + DaysHtml +
                    "</div></div><div class=\"bottom\"><input class=\"today button\" type=\"button\" value=\"今天\"/><input class=\"ok button\" type=\"button\" value=\"确定\" />" +
                    "<input class=\"cancel button\" type=\"button\" value=\"清空\" /></div></div>");


                function OK() {
                    Element._IsShowPanel = false;
                    var Day = Panel.find("i.selected").html();
                    var Value = new Date(Year, Month - 1, Day);
                    Me.val(FormatDate(Value, true));
                    Me.change();
                    Panel.remove();
                }
                function FormatDate(Date, OnlyDate) {
                    if (OnlyDate) {
                        return Date.getFullYear() + "-" + (Date.getMonth() + 1) + "-" + Date.getDate();
                    }
                    return Date.getFullYear() + "-" + (Date.getMonth() + 1) + "-" + Date.getDate() + " " + Date.getHours() + ":" + Date.getMinutes() + ":" + Date.getSeconds();
                }
                function SetLocation(Panel, Element) {
                    var ClientRect = $(Element).offset();

                    // Panel.css("width", ClientRect.width + "px");
                    Panel.css("top", (ClientRect.top + $(Element).outerHeight()) + "px");
                    Panel.css("left", ClientRect.left + "px");

                    // var IWidth = (ClientRect.width - 2) / 7;

                    // Panel.find("i").width(IWidth).height(IWidth).css("line-height", IWidth + "px");
                }

                Panel.find("input[value='>']").click(function (e) {
                    e.stopPropagation();
                    var Input = $(this.parentElement).find("input[type=text]");
                    var Value = parseInt(Input.val());
                    Input.val(Value + 1);
                    Input.trigger("change");
                });
                Panel.find("input[value='<']").click(function (e) {
                    e.stopPropagation();
                    var Input = $(this.parentElement).find("input[type=text]");
                    var Value = parseInt(Input.val());
                    Input.val(Value - 1);
                    Input.trigger("change");
                });
                Panel.find(".year input[type=text]").change(function (e) {
                    Year = parseInt($(this).val());
                    OK();
                    MeClick(e);
                }).val(Year);
                Panel.find(".month input[type=text]").change(function (e) {
                    Month = parseInt($(this).val());
                    OK();
                    MeClick(e);
                }).val(Month);
                Panel.find(".days").bind("mousewheel", function (e) {
                    if ((event.wheelDelta || e.wheelDelta) < 0) {
                        ++Month;
                    } else {
                        --Month;
                    }
                    OK();
                    MeClick(e);
                });
                Panel.find(".today").click(function () {
                    Element._IsShowPanel = false;
                    var Now = app.now();
                    Now.setHours(0);
                    Now.setMinutes(0);
                    Now.setSeconds(0);
                    Now.setMilliseconds(0);
                    Me.val(FormatDate(Now, true));
                    Me.change();
                    Panel.remove();
                });
                Panel.find(".cancel").click(function () {
                    Element._IsShowPanel = false;
                    Me.val("");
                    Me.change();
                    Panel.remove();
                });
                Panel.find(".ok").click(OK);
                Panel.find(".days i").on("click", function (e) {
                    var I = $(this);
                    e.stopPropagation();

                    Panel.find("i.selected").removeClass("selected");
                    I.addClass("selected");

                    var value = parseInt(this.innerHTML);

                    if (I.hasClass("last")) {
                        --Month;
                    } else if (I.hasClass("next")) {
                        ++Month;
                    }

                    OK();
                    MeClick(e);
                });
                Panel.click(function (e) {
                    e.stopPropagation();
                });

                app.body.append(Panel);


                SetLocation(Panel, Element);

                Panel.prop("__Element", Element);
                $(Element).prop("__DatePanel", Panel);

                function ReLayoutDatePanel() {
                    $(".date-panel").each(function () {
                        if (this.__Element) {
                            SetLocation($(this), this.__Element);
                        }
                    });
                }

                function RemoveOtherDatePanel() {
                    $(".date-panel").each(function () {
                        $($(this).prop("__Element")).prop("_IsShowPanel", false);

                        $(this).remove();
                    });
                }

                if (!window.__InitDatePanel) {

                    window.__InitDatePanel = true;

                    $(document).click(RemoveOtherDatePanel);

                    $(window).resize(ReLayoutDatePanel);

                    app.body.on("LoadBody", function () {
                        $(this).find("#Content,.content,.item,.frame").scroll(ReLayoutDatePanel);
                        $(this).find(".frame").on("Move", ReLayoutDatePanel);
                    });

                    $("#Content,.content,.item,.frame").scroll(ReLayoutDatePanel);
                    $(".frame").on("Move", ReLayoutDatePanel);
                }
            }

            Me.click(MeClick);
        }
    },
    control: function (Elements, ControlName) {
        $(Elements).each(function () {
            ControlName = ControlName || this._Control;

            this._Control = ControlName;

            app.controls[ControlName](this);
        });
    },
    loadBody: function (Data, Callback, DisableScripts) {
        var Body = app.body;

        $.ajax({
            url: Data.Url, type: "GET", data: { Version: app.version }, success: function (HTML) {
                Body.find(">*").remove();

                var Page = document.createElement("div");

                Body.append(Page);

                Page.innerHTML = HTML;

                Page = $(Page);

                var Links = Page.find("link");

                $(Links).each(function () {
                    Body.append(this);
                });

                var Scripts = Page.find("script");

                if (DisableScripts) {
                    Page.on("submit", function(e) {
                        e.stopPropagation();
                        return false;
                    });
                } else {
                    $(Scripts).each(function () {
                        if (this.src) {
                            var ScriptElement = document.createElement("script");

                            ScriptElement.src = this.src;

                            Body.appendChild(ScriptElement);
                        }

                        if (this.innerHTML) {
                            eval(this.innerHTML);
                        }
                    });
                }

                Scripts.remove();

                if (!Data.CancelRemoveUnauthorized) {
                    Page.find("[Command]").addClass("Unauthorized");

                    $(Data.Items).each(function () {
                        Page.find(this.Identifier).removeClass("Unauthorized");
                    });

                    Page.find(".Unauthorized").remove();
                }

                app.contentExtend(Page);
                app.contentLayout(Page);

                Body.triggerHandler("LoadBody");

                if (typeof Callback == "function") {
                    Callback();
                }
            }
        });
    }
};

var Render = {
    Details: function () {
        var DetailsButton = $("<a class=\"link\">详情</a>");

        DetailsButton.click(function () {
            var Row = $(this).parents("tr:first");

            Row.addClass("selected");

            var Table = $(this).parents("table:first");

            var Update = $(".update[Resource=\"" + Table.attr("id") + "\"]");

            Update.click();

            Row.removeClass("selected");
        });

        return DetailsButton;
    },
    ValueType: function (Value) {
        return {
            "1": "Boolean",
            "2": "Int",
            "4": "Long",
            "8": "Float",
            "16": "Double",
            "32": "String",
            "64": "DateTime",
            "128": "TimeSpan",
            "256": "Guid",
            "512": "Object",
            "1024": "Ids"
        }[Value] || "未定义的类型";
    },
    Date: function (Value) {
        if (Value) {
            if (typeof(Value) == "string") {
                Value = Date.parse(Value);
            }

            Value = new Date(Value);

            if (Value.getHours() == 0 && Value.getMinutes() == 0 && Value.getSeconds() == 0) {
                return Value.getFullYear() + "-" + (Value.getMonth() + 1) + "-" + Value.getDate();
            }

            return Value.getFullYear() + "-" + (Value.getMonth() + 1) + "-" + Value.getDate() + " " + Value.getHours() + ":" + Value.getMinutes() + ":" + Value.getSeconds();
        }

        return "-";
    }
};

var Base64 = new (function () {
    _keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    this.encode = function (input) {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;
        input = _utf8_encode(input);
        while (i < input.length) {
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);
            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;
            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }
            output = output +
            _keyStr.charAt(enc1) + _keyStr.charAt(enc2) +
            _keyStr.charAt(enc3) + _keyStr.charAt(enc4);
        }
        return output;
    }

    this.decode = function (input) {
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;
        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
        while (i < input.length) {
            enc1 = _keyStr.indexOf(input.charAt(i++));
            enc2 = _keyStr.indexOf(input.charAt(i++));
            enc3 = _keyStr.indexOf(input.charAt(i++));
            enc4 = _keyStr.indexOf(input.charAt(i++));
            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;
            output = output + String.fromCharCode(chr1);
            if (enc3 != 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 != 64) {
                output = output + String.fromCharCode(chr3);
            }
        }
        output = _utf8_decode(output);
        return output;
    }

    _utf8_encode = function (string) {
        string = string.replace(/\r\n/g, "\n");
        var utftext = "";
        for (var n = 0; n < string.length; n++) {
            var c = string.charCodeAt(n);
            if (c < 128) {
                utftext += String.fromCharCode(c);
            } else if ((c > 127) && (c < 2048)) {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            } else {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        }
        return utftext;
    }

    _utf8_decode = function (utftext) {
        var string = "";
        var i = 0;
        var c = c1 = c2 = 0;
        while (i < utftext.length) {
            c = utftext.charCodeAt(i);
            if (c < 128) {
                string += String.fromCharCode(c);
                i++;
            } else if ((c > 191) && (c < 224)) {
                c2 = utftext.charCodeAt(i + 1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            } else {
                c2 = utftext.charCodeAt(i + 1);
                c3 = utftext.charCodeAt(i + 2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }
        }
        return string;
    }
})();

$.extend(Array.prototype, {
    indexOf: function (element) {
        for (var i = 0; i < this.length; i++) {
            if (this[i] == element) {
                return i;
            }
        }
        return -1;
    }
});

if (!String.prototype.startsWith) {
    $.extend(String.prototype, {
        startsWith: function (text) {
            return this.indexOf(text) == 0;
        },
        endsWith: function (text) {
            return this.indexOf(text) == this.length - text.length;
        },
        trim: function () {
            return this.replace(/(^\s*)/g, "");
        }
    });
}

if (isNaN(Date.parse("1997-12-18 00:00:00"))) {
    Date.baseParse = Date.parse;
    Date.parse = function (str) {
        var match = /^([0-9]{4})-([0-9]{1,2})-([0-9]{1,2})( ([0-9]{1,2}):([0-9]{1,2}):([0-9]{1,2}))?$/.exec(str);
        if (!match) {
            return Date.baseParse(str);
        }
        var year = parseInt(match[1]);
        var month = parseInt(match[2]);
        var day = parseInt(match[3]);
        var hour = parseInt(match[5]) || 0;
        var minute = parseInt(match[6]) || 0;
        var second = parseInt(match[7]) || 0;
        return new Date(year, month - 1, day, hour, minute, second).getTime();
    }
}

if (!window.FormData) {
    app.UseIFrameSubmit = true;

    window.FormData = function () {
        this.append = function (name, value) {
            this[name] = value;
        }
    }
}

if (!window.JSON) {
    window.JSON = {
        stringify: function (obj) {
            if (typeof obj == "string") {
                var result = "";
                for (var i = 0; i < obj.length; i++) {
                    switch (obj.charAt(i)) {
                        case '\\':
                            result += "\\\\";
                            break;
                        case '"':
                            result += "\\\"";
                            break;
                        case '\n':
                            result += "\\n";
                            break;
                        case '\r':
                            result += "\\r";
                            break;
                        case '\t':
                            result += "\\t";
                            break;
                        default:
                            result += obj.charAt(i);
                    }
                }
                return '"' + result + '"';
            } else if (typeof obj == "number") {
                return String(obj);
            } else if (typeof (obj) == "boolean") {
                return obj ? "true" : "false";
            } else if (obj instanceof Date) {
                return obj.getFullYear() + "-" + (obj.getMonth() + 1) + "-" + obj.getDate() + " " + obj.getHours() + ":" + obj.getMinutes() + ":" + obj.getSeconds();
            } else if (obj instanceof Array) {
                var result = "";

                for (var i = 0; i < obj.length; ++i) {
                    result += ",";
                    result += JSON.stringify(obj[i]);
                }

                return "[" + result.substr(1) + "]";
            } else {
                var result = "";

                for (var name in obj) {
                    result += ",";
                    result += JSON.stringify(name);
                    result += ":";
                    result += JSON.stringify(obj[name]);
                }

                return "{" + result.substr(1) + "}"
            }
        },
        parse: function (text) {
            return eval("(" + text + ")");
        }
    };
}

if ((app.body.css("-webkit-user-select") ||
    app.body.css("-moz-user-select") ||
    app.body.css("-ms-user-select") ||
    app.body.css("user-select")) == undefined) {

    $(document).on("selectstart", function (e) {
        return { INPUT: true, TEXTAREA: true }[e.target.tagName] || false;
    });
}

$(window).resize(function () {
    $(".frame").each(function () {
        var me = $(this);

        if (me.hasClass("maximized")) {
            /* 只调用当前元素所绑定的 resize 事件。 */
            /* 父级的 resize 事件不会触发。 */
            me.triggerHandler("resize");
        }
    });
});

$(document).click(function (e) {
    var me = e.target;
    if (me.tagName == "LABEL") {
        me = $(me);
        var dest = me.attr("for");
        me = me.parent();
        while (dest && me.length) {
            var destElement = me.find("#" + dest);
            if (destElement.length) {
                destElement.click();
                e.stopPropagation();
                return false;
            }
            me = me.parent();
        }
    }
});